using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using OccurrencesCore.Infrastructure;

namespace OccurrencesCore.Repository
{
    /// <summary>
    /// Base class for all repositories
    /// </summary>
    /// <typeparam name="TEntity">Model entity.</typeparam>
    public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
    {
        protected DbSet<TEntity> _Repository;

        /// <summary>
        /// Default constructor
        /// </summary>
        protected BaseRepository()
        {
            _Repository = UnitOfWork.Context.Set<TEntity>();
        }

        /// <summary>
        /// Find all instances of a entity.
        /// </summary>
        /// <returns>Entity list.</returns>
        public IList<TEntity> FindAll()
        {
            return _Repository.ToList();
        }

        /// <summary>
        /// Get an entity by id
        /// </summary>
        /// <param name="id">Entity id.</param>
        /// <returns>Entity instance.</returns>
        public TEntity FindById(int id)
        {
            return _Repository.Find(id);
        }

        /// <summary>
        /// Create a new entity
        /// </summary>
        /// <param name="entity">Entity to be created.</param>
        /// <returns>Created entity</returns>
        public TEntity Create(TEntity entity)
        {
            _Repository.Add(entity);
			Save();
            return entity;
        }

		/// <summary>
        /// Create a list of entity
        /// </summary>
        /// <param name="entities">The list of entites</param>
        /// <returns>The created list of entities</returns>
        public IList<TEntity> Create(IList<TEntity> entities)
        {
            foreach (TEntity entity in entities)
            {
                _Repository.Add(entity);
            }
            Save();
            return entities;
        }

        /// <summary>
        /// Update the data of an entity
        /// </summary>
        /// <param name="entity">Entity to be updated</param>
        /// <returns>Updated entity</returns>
        public TEntity Update(TEntity entity)
        {
            UnitOfWork.Context.Entry(entity).State = System.Data.EntityState.Modified;
			Save();
            return entity;
        }

		/// <summary>
        /// Updates a list of entity
        /// </summary>
        /// <param name="entities">The list of entites</param>
        /// <returns>The updated list of entities</returns>
        public IList<TEntity> Update(IList<TEntity> entities)
        {
            foreach (TEntity entity in entities)
            {
                UnitOfWork.Context.Entry(entity).State = System.Data.EntityState.Modified;
            }
            Save();
            return entities;
        }

        /// <summary>
        /// Remove an entity by its id.
        /// </summary>
        /// <param name="id">Id of the entity to be removed.</param>
        public void Remove(int id)
        {
            TEntity entity = FindById(id);
            _Repository.Remove(entity);
			Save();
        }

        /// <summary>
        /// Remove a given entity.
        /// </summary>
        /// <param name="entity">Entity to be removed.</param>
        public void Remove(TEntity entity)
        {
            _Repository.Remove(entity);
			Save();
        }

        /// <summary>
        /// Remove a list of entities.
        /// </summary>
        /// <param name="entities">List of entities that should be removed.</param>
        public void Remove(IList<TEntity> entities)
        {
            foreach (TEntity entity in entities)
            {
                _Repository.Remove(entity);
            }
			Save();
        }

		/// <summary>
        /// Get the records of the entity based on some pagination parameters
        /// </summary>
		/// <param name="pageNumber">Number of the page desired.</param>
        /// <param name="pageSize">Number of items that is being considered for each page.</param>
		public IList<TEntity> PagedList(int pageNumber, int pageSize)
		{
			return _Repository.Skip(pageNumber * pageSize).Take(pageSize).ToList();
		}

        /// <summary>
        /// Save the changes made on a repository, this method must be called after the operations
        /// </summary>
        public void Save()
        {
            UnitOfWork.Context.SaveChanges();
        }
    }
}


